#include "binaryfile.h"
#include <QSpinBox>
#include <QCheckBox>
#include <QComboBox>
#include <QFormLayout>
#include <QFile>
#include <QDataStream>

BinaryFile::BinaryFile()
{
    numDatas = -1;
    numSpatialDimensions = -1;
    numTemporalLayers = -1;
    isRegular = false;
    numSpatialPoints = -1;
    numSpatialPointsAlongAxis1 = -1;
    numSpatialPointsAlongAxis2 = -1;
    numSpatialPointsAlongAxis3 = -1;
    dataType = EnumTypes::real8;
}

void BinaryFile::readFile()
{
    QFile *file = new QFile(filePath);
    QDataStream in(file);
    // NOTE: mind the byte order!
    in.setByteOrder(in.LittleEndian);
    file->open(QIODevice::ReadOnly);
    // create variable storing data
    if (dataType == EnumTypes::integer4) {
        data_qint32 = new QList<qint32>;
    } else if (dataType == EnumTypes::integer8) {
        data_qint64 = new QList<qint64>;
    } else if (dataType == EnumTypes::real4) {
        data_float = new QList<float>;
    } else if (dataType == EnumTypes::real8) {
        data_double = new QList<double>;
    }
    // reading
    for (int i = 0; i < this->numTemporalLayers; ++i) {
        for (int j = 0; j < this->numDatas; ++j) {
            if (this->isRegular == true) {
                int num = numSpatialPointsAlongAxis1*
                          numSpatialPointsAlongAxis2*
                          numSpatialPointsAlongAxis3;
                if (dataType == EnumTypes::integer4) {
                    qint32 data;
                    for (int k = 0; k < num; ++k) {
                        in >> data;
                        data_qint32->append(data);
                    }
                } else if (dataType == EnumTypes::integer8) {
                    qint64 data;
                    for (int k = 0; k < num; ++k) {
                        in >> data;
                        data_qint64->append(data);
                    }
                } else if (dataType == EnumTypes::real4) {
                    float data;
                    for (int k = 0; k < num; ++k) {
                        in >> data;
                        data_float->append(data);
                    }
                } else if (dataType == EnumTypes::real8) {
                    double data;
                    for (int k = 0; k < num; ++k) {
                        in >> data;
                        data_double->append(data);
                    }
                }
            } else {
                if (dataType == EnumTypes::integer4) {

                } else if (dataType == EnumTypes::integer8) {

                } else if (dataType == EnumTypes::real4) {

                } else if (dataType == EnumTypes::real8) {

                }
            }
        }
    }
}

BinaryDataFormatUI::BinaryDataFormatUI(QWidget *parent) : QWidget(parent)
{
    layout = new QFormLayout;
    spinBox_numDatas = new QSpinBox;
    spinBox_numTemporalLayers = new QSpinBox;
    spinBox_numSpatialDimensions = new QSpinBox;
    checkBox_isRegular = new QCheckBox;
    spinBox_numSpatialPoints = new QSpinBox;
    spinBox_numSpatialPointsAlongAxis1 = new QSpinBox;
    spinBox_numSpatialPointsAlongAxis2 = new QSpinBox;
    spinBox_numSpatialPointsAlongAxis3 = new QSpinBox;
    comboBox_dataType = new QComboBox;

    spinBox_numDatas->setRange(1, 100);
    spinBox_numTemporalLayers->setRange(1, 10000);
    spinBox_numSpatialDimensions->setRange(1, 3);
    spinBox_numSpatialPoints->setRange(1, 10000);
    spinBox_numSpatialPointsAlongAxis1->setRange(1, 10000);
    spinBox_numSpatialPointsAlongAxis2->setRange(1, 10000);
    spinBox_numSpatialPointsAlongAxis3->setRange(1, 10000);
    spinBox_numSpatialPointsAlongAxis1->setDisabled(true);
    spinBox_numSpatialPointsAlongAxis2->setDisabled(true);
    spinBox_numSpatialPointsAlongAxis3->setDisabled(true);
    comboBox_dataType->addItem("integer 4");
    comboBox_dataType->addItem("integer 8");
    comboBox_dataType->addItem("real 4");
    comboBox_dataType->addItem("real 8");

    connect(checkBox_isRegular, SIGNAL(clicked(bool)), this, SLOT(setSpatialPointsMode(bool)));

    layout->addRow(tr("number of datas:"), spinBox_numDatas);
    layout->addRow(tr("number of temporal layers:"), spinBox_numTemporalLayers);
    layout->addRow(tr("number of spatial dimensions:"), spinBox_numSpatialDimensions);
    layout->addRow(tr("regular spatial distribution:"), checkBox_isRegular);
    layout->addRow(tr("number of spatial points:"), spinBox_numSpatialPoints);
    layout->addRow(tr("number of spatial points along 1st axis:"), spinBox_numSpatialPointsAlongAxis1);
    layout->addRow(tr("number of spatial points along 2nd axis:"), spinBox_numSpatialPointsAlongAxis2);
    layout->addRow(tr("number of spatial points along 3rd axis:"), spinBox_numSpatialPointsAlongAxis3);
    layout->addRow(tr("data type in byte:"), comboBox_dataType);
    this->setLayout(layout);
}

void BinaryDataFormatUI::setFrom(const BinaryFile &binaryFile)
{
    spinBox_numDatas->setValue(binaryFile.numDatas);
    spinBox_numTemporalLayers->setValue(binaryFile.numTemporalLayers);
    spinBox_numSpatialDimensions->setValue(binaryFile.numSpatialDimensions);
    spinBox_numSpatialPoints->setValue(binaryFile.numSpatialPoints);
    spinBox_numSpatialPointsAlongAxis1->setValue(binaryFile.numSpatialPointsAlongAxis1);
    spinBox_numSpatialPointsAlongAxis2->setValue(binaryFile.numSpatialPointsAlongAxis2);
    spinBox_numSpatialPointsAlongAxis3->setValue(binaryFile.numSpatialPointsAlongAxis3);
    checkBox_isRegular->setChecked(binaryFile.isRegular);
    if (binaryFile.isRegular == true) {
        spinBox_numSpatialPoints->setDisabled(true);
        switch (binaryFile.numSpatialDimensions) {
        case (1) :
            spinBox_numSpatialPointsAlongAxis1->setEnabled(true);
            break;
        case (2) :
            spinBox_numSpatialPointsAlongAxis1->setEnabled(true);
            spinBox_numSpatialPointsAlongAxis2->setEnabled(true);
            break;
        case (3) :
            spinBox_numSpatialPointsAlongAxis1->setEnabled(true);
            spinBox_numSpatialPointsAlongAxis2->setEnabled(true);
            spinBox_numSpatialPointsAlongAxis3->setEnabled(true);
            break;
        }
    } else {
        spinBox_numSpatialPointsAlongAxis1->setDisabled(true);
        spinBox_numSpatialPointsAlongAxis2->setDisabled(true);
        spinBox_numSpatialPointsAlongAxis3->setDisabled(true);
    }
}

void BinaryDataFormatUI::setTo(BinaryFile *binaryFile)
{
    int temp = binaryFile->numDatas;
    binaryFile->numDatas = spinBox_numDatas->value();
    for (int i = temp; i < binaryFile->numDatas; ++i)
        binaryFile->dataNameList.append(QString("data %1").arg(i));
    binaryFile->numTemporalLayers = spinBox_numTemporalLayers->value();
    binaryFile->numSpatialDimensions = spinBox_numSpatialDimensions->value();
    binaryFile->isRegular = checkBox_isRegular->isChecked();
    binaryFile->numSpatialPoints = spinBox_numSpatialPoints->value();
    binaryFile->numSpatialPointsAlongAxis1 = spinBox_numSpatialPointsAlongAxis1->value();
    binaryFile->numSpatialPointsAlongAxis2 = spinBox_numSpatialPointsAlongAxis2->value();
    binaryFile->numSpatialPointsAlongAxis3 = spinBox_numSpatialPointsAlongAxis3->value();
}

void BinaryDataFormatUI::disable()
{
    spinBox_numDatas->setDisabled(true);
    spinBox_numTemporalLayers->setDisabled(true);
    spinBox_numSpatialDimensions->setDisabled(true);
    checkBox_isRegular->setDisabled(true);
    spinBox_numSpatialPoints->setDisabled(true);
    spinBox_numSpatialPointsAlongAxis1->setDisabled(true);
    spinBox_numSpatialPointsAlongAxis2->setDisabled(true);
    spinBox_numSpatialPointsAlongAxis3->setDisabled(true);
    comboBox_dataType->setDisabled(true);
}

void BinaryDataFormatUI::enable()
{
    spinBox_numDatas->setEnabled(true);
    spinBox_numTemporalLayers->setEnabled(true);
    spinBox_numSpatialDimensions->setEnabled(true);
    checkBox_isRegular->setEnabled(true);
    if (checkBox_isRegular->isChecked() == true) {
        switch (spinBox_numSpatialDimensions->value()) {
        case (1) :
            spinBox_numSpatialPointsAlongAxis1->setEnabled(true);
        case (2) :
            spinBox_numSpatialPointsAlongAxis1->setEnabled(true);
            spinBox_numSpatialPointsAlongAxis2->setEnabled(true);
        case (3) :
            spinBox_numSpatialPointsAlongAxis1->setEnabled(true);
            spinBox_numSpatialPointsAlongAxis2->setEnabled(true);
            spinBox_numSpatialPointsAlongAxis3->setEnabled(true);
        }
    } else {
        spinBox_numSpatialPoints->setEnabled(true);
    }
    comboBox_dataType->setEnabled(true);
}

void BinaryDataFormatUI::setSpatialPointsMode(bool flag)
{
    if (flag == true) {
        spinBox_numSpatialPoints->setDisabled(true);
        switch (spinBox_numSpatialDimensions->value()) {
        case (1) :
            spinBox_numSpatialPointsAlongAxis1->setEnabled(true);
            break;
        case (2) :
            spinBox_numSpatialPointsAlongAxis1->setEnabled(true);
            spinBox_numSpatialPointsAlongAxis2->setEnabled(true);
            break;
        case (3) :
            spinBox_numSpatialPointsAlongAxis1->setEnabled(true);
            spinBox_numSpatialPointsAlongAxis2->setEnabled(true);
            spinBox_numSpatialPointsAlongAxis3->setEnabled(true);
            break;
        }
    } else {
        spinBox_numSpatialPoints->setEnabled(true);
        spinBox_numSpatialPointsAlongAxis1->setDisabled(true);
        spinBox_numSpatialPointsAlongAxis2->setDisabled(true);
        spinBox_numSpatialPointsAlongAxis3->setDisabled(true);
    }
}
